package net.begincode.blog.service.impl;

import com.alibaba.druid.sql.parser.Keywords;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.begincode.blog.UserContext;
import net.begincode.blog.bean.param.BlogClassQueryParam;
import net.begincode.blog.bean.param.BlogQueryParam;
import net.begincode.blog.bean.vo.BlogBaseInfo;
import net.begincode.blog.bean.vo.BlogWithKeyWords;
import net.begincode.blog.bean.vo.CheckBlog;
import net.begincode.blog.bean.vo.KeyWord;
import net.begincode.blog.dao.biz.*;
import net.begincode.blog.entity.*;
import net.begincode.blog.enums.BlogFlagEnum;
import net.begincode.blog.service.BlogService;
import net.begincode.page.PageResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class BlogServiceImpl implements BlogService {
    private static final Joiner JOINER = Joiner.on(",").skipNulls();
    @Resource
    private BlogKeyWordsBizMapper blogKeyWordsBizMapper;
    @Resource
    private HomeTypeBlogBizMapper homeTypeBlogBizMapper;
    @Resource
    private KeyWordsBizMapper keyWordsBizMapper;
    @Resource
    private BlogBizMapper blogBizMapper;
    @Resource
    private HomeTypeRecommendBizMapper homeTypeRecommendBizMapper;

    @Override
    @Transactional
    public int addBlogKeyWords(Long blogId, List<Long> keyWordIds) {
        if (blogId == null || CollectionUtils.isEmpty(keyWordIds)) {
            return 0;
        }
        List<BlogKeyWords> blogKeyWordList = keyWordIds.stream().map(keyWordId -> {
            BlogKeyWords blogKeyWords = new BlogKeyWords();
            blogKeyWords.setBlogId(blogId);
            blogKeyWords.setKeyWordId(keyWordId);
            blogKeyWords.setOperator(Long.valueOf(UserContext.getUserInfo().getId()));
            return blogKeyWords;
        }).collect(Collectors.toList());
        blogKeyWordsBizMapper.delBlogKeyWords(blogId, Lists.newArrayList());
        return blogKeyWordsBizMapper.insertBatch(blogKeyWordList);
    }

    @Override
    @Transactional
    public int delBlogKeyWords(Long blogId, List<Long> keyWordIds) {
        if (blogId == null || CollectionUtils.isEmpty(keyWordIds)) {
            return 0;
        }
        return blogKeyWordsBizMapper.delBlogKeyWords(blogId, keyWordIds);
    }

    @Override
    @Transactional
    public int addOrUpdateHomeTypeBlog(Long blogId, Long homeTypeId) {
        Preconditions.checkNotNull(blogId, "blogId not null");
        Preconditions.checkNotNull(homeTypeId, "homeTypeId not null");
        HomeTypeBlog homeTypeBlog = new HomeTypeBlog();
        homeTypeBlog.setBlogId(blogId);
        homeTypeBlog.setHomeTypeId(homeTypeId);
        homeTypeBlog.setCdate(new Date());
        homeTypeBlog.setOperator(UserContext.getUserInfo().getId());
        return homeTypeBlogBizMapper.addOrUpdateHomeTypeBlog(homeTypeBlog);
    }

    @Override
    public int updateBlog(Blog blog) {
        Preconditions.checkNotNull(blog, "blog not null");
        Preconditions.checkNotNull(blog.getId(), "blog id not null");
        return blogBizMapper.updateByPrimaryKeySelective(blog);
    }

    @Override
    @Transactional
    public PageResponse<CheckBlog> selectCheckBlog(BlogQueryParam queryParam) {
        Preconditions.checkNotNull(queryParam, "queryParam not null");
        int totalCount = blogBizMapper.countByParam(queryParam);
        if (totalCount == 0) {
            return PageResponse.empty(queryParam.getPageNo(), queryParam.getPageSize());
        }
        List<CheckBlog> checkBlogs = blogBizMapper.selectByParam(queryParam, queryParam.getOffset(), queryParam.getLimit());

        return PageResponse.success(fillKeyWords(checkBlogs), queryParam.getPageNo(), queryParam.getPageSize(), totalCount);
    }

    private List<CheckBlog> fillKeyWords(List<CheckBlog> checkBlogs) {
        List<Long> blogIds = net.begincode.common.CollectionUtils.safes(checkBlogs).stream()
                .map(CheckBlog::getId).collect(Collectors.toList());
        List<BlogKeyWords> blogKeyWords = blogKeyWordsBizMapper.selectByBlogIds(blogIds);
        Map<Long, List<BlogKeyWords>> blogKeyWordsMap = net.begincode.common.CollectionUtils.safes(blogKeyWords)
                .stream().collect(Collectors.groupingBy(BlogKeyWords::getBlogId));

        List<Long> keywordIds = net.begincode.common.CollectionUtils.safes(blogKeyWords)
                .stream().map(BlogKeyWords::getKeyWordId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(keywordIds)){
            return checkBlogs;
        }
        Map<Long, KeyWords> keywordsMap = net.begincode.common.CollectionUtils.safes(keyWordsBizMapper.queryByIds(keywordIds))
                .stream().collect(Collectors.toMap(KeyWords::getId, java.util.function.Function.identity()));

        for(CheckBlog checkBlog : checkBlogs){
            if(blogKeyWordsMap.containsKey(checkBlog.getId())){
                Set<String> blogKeys = Sets.newHashSet();
                for(BlogKeyWords blogkey:blogKeyWordsMap.get(checkBlog.getId()) ){
                    if(keywordsMap.containsKey(blogkey.getKeyWordId())){
                        blogKeys.add(keywordsMap.get(blogkey.getKeyWordId()).getKeyWord());
                    }
                }
                checkBlog.setKeyWords(JOINER.join(blogKeys));
            }
        }
        return checkBlogs;
    }


    @Override
    public List<BlogBaseInfo> selectEffectByIds(List<Long> blogIds) {
        if (CollectionUtils.isEmpty(blogIds)) {
            return Lists.newArrayList();
        }
        return blogBizMapper.selectByIds(blogIds, BlogFlagEnum.PUBLIC.getFlagCode());
    }

    @Override
    public BlogWithKeyWords queryBlogById(Long blogId, String blogFlag) {
        BlogWithKeyWords blogWithKeyWords = new BlogWithKeyWords();
        Blog blog = blogBizMapper.selectById(blogId, blogFlag);
        if (Objects.isNull(blog)) {
            return null;
        }
        blogWithKeyWords.setBlog(blog);
        List<Long> keyWordsId = net.begincode.common.CollectionUtils.safes(blogKeyWordsBizMapper.selectByBlogId(blogId))
                .stream().map(BlogKeyWords::getKeyWordId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(keyWordsId)) {
            blogWithKeyWords.setKeyWords(net.begincode.common.CollectionUtils
                    .safes(keyWordsBizMapper.queryByIds(keyWordsId))
                    .stream()
                    .map(keyWords -> {
                        KeyWord keyWord = new KeyWord();
                        keyWord.setKeyWord(keyWords.getKeyWord());
                        keyWord.setKeyWordId(keyWords.getId());
                        return keyWord;
                    })
                    .collect(Collectors.toList()));
        }
        return blogWithKeyWords;
    }

    @Override
    public int countClass(BlogClassQueryParam queryParam) {
        Preconditions.checkNotNull(queryParam, "queryParam not null");
        Preconditions.checkArgument(Objects.nonNull(queryParam.getKeyWordId()) || Objects.nonNull(queryParam.getBlogTypeId()),
                "keywordId and homeTypeId not all null");
        return blogBizMapper.countClassify(queryParam.getBlogTypeId(), queryParam.getKeyWordId());
    }

    @Override
    public List<Blog> selectClass(BlogClassQueryParam queryParam) {
        Preconditions.checkNotNull(queryParam, "queryParam not null");
        Preconditions.checkArgument(Objects.nonNull(queryParam.getKeyWordId()) || Objects.nonNull(queryParam.getBlogTypeId()),
                "keywordId and homeTypeId not all null");
        return blogBizMapper.selectClassify(queryParam.getBlogTypeId(), queryParam.getKeyWordId()
                , queryParam.getOffset(), queryParam.getLimit());
    }

    @Override
    public List<BlogBaseInfo> queryRecommend(Long homeTypeId, int limit) {
        Preconditions.checkArgument(limit > 0, "limit must > 0");
        List<Long> blogIds = net.begincode.common.CollectionUtils.safes(homeTypeRecommendBizMapper.selecRecommend(homeTypeId, limit))
                .stream().map(HomeTypeRecommend::getBlogId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(blogIds)) {
            return Lists.newArrayList();
        }
        return blogBizMapper.selectByIds(blogIds, BlogFlagEnum.PUBLIC.getFlagCode());
    }

    @Override
    public List<Blog> selectTopN(String flag, int limit) {
        return blogBizMapper.selectTopN(flag, limit);
    }
}
